import { UploadOutlined } from '@ant-design/icons';
import type { UploadFile, UploadProps } from 'antd';
import { Button, message, Upload } from 'antd';
import { useState } from 'react';

import { mergeVideo, uploadVideo } from '../../services/upload';
import { getHash } from '../../utils/getHash';

type Chunk = {
  file: Blob;
  uploaded: boolean;
  fileHash: string;
  chunkIndex: number;
};

export default function UploadPage() {
  const [fileList, setFileList] = useState<UploadFile[]>([]);

  const props: UploadProps = {
    name: 'file',
    action: 'http://localhost:3000/api/upload',
    beforeUpload: () => false,
    onChange(info) {
      const { fileList } = info;
      setFileList([fileList[0]]);
    },
  };

  function createChunks(file: File, fileHash: string): Chunk[] {
    // 使用单独常量保存预设切片大小 1MB
    const chunkSize = 1024 * 1024 * 5;
    // 接受一个文件对象，要把这个文件对象切片，返回一个切片数组
    const chunks = [];
    // 文件大小.slice(开始位置,结束位置)
    let start = 0;
    let index = 0;
    while (start < file.size) {
      const curChunk = file.slice(start, start + chunkSize);
      chunks.push({
        file: curChunk,
        uploaded: false,
        fileHash: fileHash,
        chunkIndex: index,
      });
      index++;
      start += chunkSize;
    }
    return chunks;
  }

  const uploadHandler = (chunk: Chunk) => {
    return new Promise((resolve, reject) => {
      const blob = chunk.file;
      return uploadVideo({
        file: blob,
        fileHash: chunk.fileHash,
        chunkIndex: chunk.chunkIndex,
      })
        .then(res => {
          resolve(res);
        })
        .catch(err => {
          reject(err);
        })
        .finally(() => {
          chunk.uploaded = true;
        });
    });
  };

  // 批量上传切片
  const uploadChunks = (chunks: Chunk[], maxConcurrency = 6) => {
    return new Promise((resolve, reject) => {
      if (chunks.length == 0) {
        resolve([]);
      }
      const results = new Array(chunks.length);
      let currentIndex = 0;
      let completedCount = 0;
      let hasError = false;

      const startNext = () => {
        if (hasError) return;

        const index = currentIndex;
        if (index >= chunks.length) return;
        currentIndex++;

        uploadHandler(chunks[index])
          .then(result => {
            results[index] = result;
            completedCount++;
            if (completedCount === chunks.length) {
              resolve(results);
            } else {
              startNext();
            }
          })
          .catch((err: Error) => {
            if (!hasError) {
              hasError = true;
              reject(err);
            }
          });
      };

      for (let i = 0; i < Math.min(maxConcurrency, chunks.length); i++) {
        startNext();
      }
    });
  };

  async function uploadFile(file: File, fileHash: string) {
    const chunks = createChunks(file, fileHash);
    await uploadChunks(chunks);
  }

  async function mergeRequest(fileHash: string, fileName: string) {
    return await mergeVideo({
      fileHash,
      fileName,
    });
  }

  async function handleSubmit() {
    console.log('fileList:', fileList);
    const file = fileList[0].originFileObj!;
    if (!file) {
      message.error('请上传视频');
      return;
    }
    const formData = new FormData();
    formData.append('file', file);
    // 设置文件名
    const fileName = file.name;
    // 获取文件hash值
    const fileHash = await getHash(file, (percent: number) => {
      console.log('percent:', percent);
    });
    console.log('fileHash:', fileHash);

    await uploadFile(file, fileHash);
    await mergeRequest(fileHash, fileName);
  }

  return (
    <div>
      <Upload {...props}>
        <Button icon={<UploadOutlined />}>上传视频</Button>
      </Upload>
      <Button onClick={handleSubmit}>提交</Button>
    </div>
  );
}
